<?php

namespace brand\logic;

use brand\Brand;
use brand\Curd;
use brand\page\Page;
use brand\tools\Functions;
use think\facade\Db;

class Database
{
    /**
     * 表前缀
     *
     * @var string
     */
    protected static $prefix = '';

    /**
     * 所有数据库表详情
     *
     * @param string $table
     *
     * @return array
     */
    public static function tablesInfo(string $table = '', $getSystemTable = 0)
    {

        $prefix = self::getPrefix();
        if ($table)
        {
            $table = static::sqlFilter($table);
            $table = " AND TABLE_NAME = '{$prefix}{$table}'";
        }

        $sql
            = "SELECT TABLE_NAME as `table`,TABLE_COMMENT as `comment`,TABLE_ROWS as `rows`,ENGINE as `engine` FROM information_schema.TABLES WHERE TABLE_SCHEMA = :table "
            .$table;
        $list = Db::instance()->query($sql, ['table' => Db::instance()->getConfig(Config::DATABASE_CONFIG_LOCATION)]);

        $res = [];
        foreach ($list as $k => $v)
        {
            $table = $prefix && 0 === strpos($v['table'], $prefix) ? substr($v['table'], strlen($prefix)) : $v['table'];
            if ($getSystemTable == 0 && in_array($table,Config::DEFAULT_DATABASE)) {
                continue;
            }
            $res[] = [
                'table'          => $table,
                'title'          => $v['comment'],
                'description'    => $v['comment'],
                'rows'           => $v['rows'],
                'engine'         => $v['engine']
            ];
        }

        return $res;
    }

    /**
     * 获取字段详情
     * @param $table
     * @return array
     */
    public static function getTableFields($table)
    {
        $prefix = self::getPrefix();
        $schema = Db::instance()->getConfig(Config::DATABASE_CONFIG_LOCATION);
        $fields = Db::query("select * from information_schema.COLUMNS where table_name = '{$prefix}{$table}' and table_schema = '{$schema}'");
        if (!$fields) return [];

        $resFields = [];

        foreach ($fields as $field) {
            $_resFields = [];
            if (isset($resFields[$field['COLUMN_NAME']])) continue;
            $_resFields['name'] = $field['COLUMN_NAME'];
            $_resFields['order'] = $field['ORDINAL_POSITION'];
            $_resFields['is_null'] = $field['IS_NULLABLE'];
            $_resFields['data_type'] = $field['DATA_TYPE'];
            $_resFields['key'] = $field['COLUMN_KEY'];
            $_resFields['extar'] = $field['EXTRA'];
            $_resFields['comment'] = $field['COLUMN_COMMENT'];
            $_resFields['default'] = $field['COLUMN_DEFAULT'];
            $_resFields['date_table'] = $table;
            $resFields[$field['COLUMN_NAME']] = $_resFields;
        }

        return $resFields;

    }


    /**
     * 获取表格详情
     * @param array $fields
     * @return array
     */
    public static function fieldsToColumns(array $fields = [])
    {
        $columns = [];

        foreach ($fields as $field) {

            //根据备注获取信息
            $comment = self::curdComment($field['comment'],$field['name']);
            //获取方法

            $fromTable = self::curdMethodByName($field,$comment['method'] ?? "");

            $fromTable['title'] = $comment['title'];
            if (isset($comment['special_type']) && $comment['special_type']){
                $fromTable['special_type'] = $comment['special_type'];
            }
            $_columns[$field['name']] = $fromTable;

            $columns = $_columns;

        }

        return $columns;
    }


    /**
     * 构建关联字段
     * @param $columns
     * @return array
     */
    public static function buildRelevancy($columns)
    {
        $res_columns = [];
        foreach ($columns as $key => $column) {
            //先删除掉对应的键，防止重复
            if (isset($column['form']['is_relevancy'])){
                unset($columns[$key]);
                continue;
            }
            //找take属性的字段
            if (isset($column['table']['relevancy']) && isset($column['table']['relevancy_labels'])){
                //获取管理字段配置
                $table_conf = BrandHelper::getCurdConfigByName($column['table']['relevancy']);
                foreach ($column['table']['relevancy_labels'] as $relevancy_label) {
                    if (isset($table_conf['columns'][$relevancy_label])){
                        //要关联的表配置
                        $relevancy_column = $table_conf['columns'][$relevancy_label] ?? [];
                        //表单关联判断
                        $relevancy_column['form']['is_relevancy'] = 1;
                        //远程关联键
                        $relevancyPk = isset($relevancy_column['model']['pk']) ? ( $relevancy_column['model']['pk'] ?: 'id' ) : 'id';
                        $relevancy_column['table']['table_relevancy_key'] = $relevancyPk;
                        //本地关联键
                        $relevancy_column['table']['table_location_key'] = $key;
                        $relevancy_column['title'] = '['.$table_conf['title'] .']'. $relevancy_column['title'];
                        //插入配置
                        $res_columns[$column['table']['relevancy'] . '__BA__' . $relevancy_label] = $relevancy_column;
                    }
                }

            }
            $res_columns[$key] = $column;
        }

        return $res_columns;

    }

    public static function buildPageByTable($table, $fields = null)
    {
        if (!$fields) $fields = self::getTableFields($table);
        $tableInfo = self::tablesInfo($table)[0] ?? [];
        $page = [];
        $pk = self::getPkByTable($table, $fields);
        $table = BrandHelper::addonGetPrefix($table);
        $page['table'] = $table;
        $page['title'] = $tableInfo['title'] ?? '';
        $page['header_buttons'] = Config::$header_buttons;
        $page['right_buttons'] = Config::$right_buttons;
        $page['pk'] = $pk;
        return $page;

    }

    public static function getPkByTable($table, $fields = null)
    {
        if (!$fields) $fields = self::getTableFields($table);
        $pk = "";
        foreach ($fields as $field) {
            if(isset($field['key']) && $field['key'] == 'PRI'){
                $pk = $field['name'];
                break;
            }
        }
        return $pk;
    }

    public static function curdMethodByName($field,$method = "")
    {

        $name = $field['name'] ?? "";

        $column = null;

        $ClassName = Config::BRAND_NAMESPACE;

        //dateType

        if ($field['data_type'] == 'enum'){

            //下拉框 单选
            $ClassName .= 'Select';
            $column = ( new $ClassName() )->DbToCurd($field,['multiple'=>false]);


        }elseif ($field['data_type'] == 'set'){

            //下拉框 多选
            $ClassName .= 'Select';
            $column = ( new $ClassName() )->DbToCurd($field,['multiple'=>true]);

        }elseif (!Functions::endStr($name,'content') && $field['data_type'] == 'text'){

            //textaea表单输入
            $ClassName .= 'Input';
            $column = ( new $ClassName() )->DbToCurd($field,['type'=>'textarea']);


        }elseif ($field['data_type'] == 'datetime' || $field['data_type'] == 'timestamp'){

            //时间日期
            $ClassName .= 'Date';
            $column = ( new $ClassName() )->DbToCurd($field,[
                'value-format' => 'yyyy-MM-dd HH:mm:ss',
                'type' => 'datetime',
            ]);


        }elseif ($field['data_type'] == 'date'){

            //时间日期
            $ClassName .= 'Date';
            $column = ( new $ClassName() )->DbToCurd($field,[
                'value-format' => 'yyyy-MM-dd',
                'type' => 'date',
            ]);

        }elseif ($field['data_type'] == 'time'){

            //时间
            $ClassName .= 'Time';
            $column = ( new $ClassName() )->DbToCurd($field,[
                'value-format' => 'HH:mm:ss',
            ]);


        }elseif ($field['data_type'] == 'json'){

            //Arrays
            $ClassName .= 'Arrays';
            $column = ( new $ClassName() )->DbToCurd($field);


        }else{
            //特殊字符串结尾的
            if ($method == 'time' || Functions::endStr($name,'time')){

                //日期时间类型的时间戳
                $ClassName .= 'Date';
                $column = ( new $ClassName() )->DbToCurd($field,[
                    'value-format' => 'timestamp',
                    'type' => 'datetime',
                ]);



            }elseif($method == 'date' || Functions::endStr($name,'date')){

                //时间日期
                $ClassName .= 'Date';
                $column = ( new $ClassName() )->DbToCurd($field,[
                    'value-format' => 'yyyy-MM-dd',
                    'type' => 'date',
                ]);

            }elseif($method == 'time_range' || Functions::endStr($name,'time_range')){
                //时间区间
                $ClassName .= 'Time';
                $column = ( new $ClassName() )->DbToCurd($field,[
                    'value-format' => 'HH:mm:ss',
                    'isRange'=> true
                ]);

            }elseif($method == 'date_range' || Functions::endStr($name,'date_range')){
                //日期区间
                $ClassName .= 'Date';
                $column = ( new $ClassName() )->DbToCurd($field,[
                    'value-format' => 'yyyy-MM-dd HH:mm:ss',
                    'type'=>'datetimerange'
                ]);

            }elseif($method == 'images' || Functions::endStr($name,'images')){
                //多图片
                $ClassName .= 'Upload';
                $column = ( new $ClassName() )->DbToCurd($field,[
                    'limit' => 999
                ]);

            }elseif($method == 'image' || Functions::endStr($name,'image') || $method == 'avatar' || Functions::endStr($name,'avatar')){

                //单图片
                $ClassName .= 'Upload';
                $column = ( new $ClassName() )->DbToCurd($field);

            }elseif($method == 'files' || Functions::endStr($name,'files')){
                //多文件
                $ClassName .= 'Upload';
                $column = ( new $ClassName() )->DbToCurd($field,[
                    'limit' => 999,
                    'fileType'    =>  'file'
                ]);

            }elseif($method == 'file' || Functions::endStr($name,'file')){

                //单文件
                $ClassName .= 'Upload';
                $column = ( new $ClassName() )->DbToCurd($field,[
                    'fileType'    =>  'file'
                ]);

            }elseif( ($method == 'content' || Functions::endStr($name,'content'))  && $field['data_type'] == 'text'){
                //编辑器
                $ClassName .= 'Editor';
                $column = ( new $ClassName() )->DbToCurd($field);

            }elseif($method == 'lists' || Functions::endStr($name,'lists')){

                //下拉框 多选
                $ClassName .= 'Select';
                $column = ( new $ClassName() )->DbToCurd($field,['multiple'=>true]);


            }elseif($method == 'list' || Functions::endStr($name,'list')){

                //下拉框 单选
                $ClassName .= 'Select';
                $column = ( new $ClassName() )->DbToCurd($field,['multiple'=>false]);

            }elseif($method == 'datas' || $method == 'checkbox' || Functions::endStr($name,'datas')){

                //多选框
                $ClassName .= 'Checkbox';
                $column = ( new $ClassName() )->DbToCurd($field,['multiple'=>true]);

            }elseif($method == 'data' || $method == 'radio' || Functions::endStr($name,'data')){

                //单框
                $ClassName .= 'Radio';
                $column = ( new $ClassName() )->DbToCurd($field);


            }elseif($method == 'switch' || Functions::endStr($name,'switch')){

                //开关
                $ClassName .= 'Switcher';
                $column = ( new $ClassName() )->DbToCurd($field);

            }elseif($method == 'status' || Functions::endStr($name,'status')){

                //单框
                $ClassName .= 'Switcher';
                $column = ( new $ClassName() )->DbToCurd($field);

            }elseif( ( $method == 'number' || Functions::endStr($name,'number') )  && self::isIntType($field['data_type'])){

                //数字
                $ClassName .= 'Number';
                $column = ( new $ClassName() )->DbToCurd($field);

            }elseif( $method == 'color' || Functions::endStr($name,'color')){

                //颜色
                $ClassName .= 'Color';
                $column = ( new $ClassName() )->DbToCurd($field);

            }elseif( $method == 'rate' || Functions::endStr($name,'rate')){

                //评分
                $ClassName .= 'Rate';
                $column = ( new $ClassName() )->DbToCurd($field);

            }elseif( $method == 'slider' || Functions::endStr($name,'slider')){

                //评分
                $ClassName .= 'Slider';
                $column = ( new $ClassName() )->DbToCurd($field);

            }elseif($method == 'json' || Functions::endStr($name,'json') || $method == 'array' || Functions::endStr($name,'array')){

                //数组
                $ClassName .= 'Arrays';
                $column = ( new $ClassName() )->DbToCurd($field);

            }elseif( $field['key'] != 'PRI' && Functions::endStr($name,'_ids')){

                //Take 表格中选择
                $ClassName .= 'Take';
                $column = ( new $ClassName() )->DbToCurd($field,['limit'=>9999]);
                //联表

            }elseif( $field['key'] != 'PRI' && Functions::endStr($name,'_id')){

                //Take 表格中选择
                $ClassName .= 'Take';
                $column = ( new $ClassName() )->DbToCurd($field);

            }elseif( $method == 'select' ){
                $ClassName .= 'Select';
                $column = ( new $ClassName() )->DbToCurd($field);
            }

        }

        //未捕捉到数据
        if (!$column){
            //数字类型
            if ( self::isIntType($field['data_type'])){
                $ClassName .= 'Number';
                $column = ( new $ClassName() )->DbToCurd($field);
            }else{
                $column = Brand::Builder()->search_condition('like');
            }
        }


        //TODO 默认值

        //主键
        if ($field['key'] == 'PRI'){
            $column->form_method('hidden')->form_props(['sortable' => true])->search_condition('=');
        }



        //验证规则
        if (isset($field['is_null']) && $field['is_null'] == 'NO'){
            $column->form_validate([ ['required'=>true] ]);
        }

        $column_array = is_object($column) ? $column->build() : [];

        $column_array['field'] = $field;
        return $column_array;


        
    }
    /**
     * 根据备注获取信息
     * @param $comment
     * @return array
     */
    public static function curdComment($comment,$field = "")
    {
        if (!$comment) $comment = $field;

        $array = explode('@',$comment);
        $title = "";
        $method = "";
        $params = "";
        $paramsArray = [];
        $optionsArray = [];

        foreach ($array as $key => $item) {
            if ($key == 0){
                $title = $item;
            }else{
                $method .= $item;
            }
        }
        //循环后面的
        $params_str = explode(':',$method ?: $title);
        foreach ($params_str as $key => $item) {
            if ($method && $key == 0){
                $method = $item;
            }elseif (!$method && $key == 0){
                $title = $item;
            }else{
                $params .= $item;
            }
        }
        if ($params){
            $params_arr = explode('&',$params);

            foreach ($params_arr as $param) {
                $arr = explode('=',$param);
                $paramsArray[] = [
                    'value' =>  $arr[0] ?? '',
                    'label' =>  $arr[1] ?? '',
                ];
                $optionsArray[$arr[0] ?? ''] =  $arr[1] ?? '';
            }
        }

        $res['title'] = $title;
        $res['method'] = $method;
        $res['params'] = $paramsArray;
        $res['options'] = $optionsArray;
        if (isset(Config::SPECIAL_TYPE[$field])){
            $res['special_type'] = $field;
        }


        return  $res;

    }


    public static function setPrefix($prefix)
    {
        self::$prefix = self::getPrefix() . $prefix;
    }

    public static function getPrefix()
    {
        return self::$prefix ?: self::$prefix = Db::instance()->getConfig(Config::PREFIX_CONFIG_LOCATION);
    }

    /**
     * sql注入过滤
     * @param string $str
     * @return string
     */
    protected static function sqlFilter(string $str): string
    {
        $str = addslashes($str);

        $str = str_replace("%", "\%", $str);

        $str = nl2br($str);

        return htmlspecialchars($str);
    }

    public static function isIntType($type)
    {
        return in_array($type , ['tinyint','smallint', 'mediumint', 'int','intterger', 'bigint','float','double','dec','decimal']);
    }

    public static function isFloatType($type)
    {
        return in_array($type , ['float','double','dec','decimal']);
    }

    public static function takeTables()
    {
        $tables = self::tablesInfo('',1);
        $options = [];
        foreach ($tables as $table) {
            $fields = self::getTableFields($table['table']);
            $children = [];

            foreach ($fields as $field) {

                //显示的数据
                /*
                $relevancy_labels = [];
                foreach ($fields as $items) {
                    $comment = self::curdComment($items['comment']);
                    $relevancy_labels[] = [
                        'value' =>  $items['name'],
                        'label' =>  ($items['name'] . '【'.($comment['title'] ?? $items['name']).'】'),
                    ];
                }
                */
                $comment = self::curdComment($field['comment'],$field['name']);
                //关联的主键
                $children[] = [
                    'value' =>  $field['name'],
                    'label' =>  ($field['name'] . '【'.($comment['title'] ?? $field['name']).'】'),
//                    'children'  =>  $relevancy_labels
                ];
            }
            //表
            $options[] = [
                'value' =>  $table['table'],
                'label' =>  ($table['table'] . '【'.($table['title'] ?? $table['table']).'】'),
                'children' =>  $children,
            ];
        }
        return $options;
    }

}